package com.world.business.user.service;

import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;

/**
 * 八字
 */
public class BaZi {
    /**
     * 定义天干
     */
    static final String[] tenHeavenlyStems = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
    /**
     * 定义地支
     */
    static final String[] twelveEarthlyBranches = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
    /**
     * 世纪
     */
    static int century;
    /**
     * 年
     */
    static int year;
    /**
     * 阳历年后两位
     */
    static int yearTwo;
    /**
     * 阳历年前两位
     */
    static int twoYear;
    /**
     * 阳历月
     */
    static int month;
    /**
     * 阳历日
     */
    static int day;
    /**
     * 农历月
     */
    static int chineseMonth;
    /**
     * 农历日
     */
    static int chineseDay;
    /**
     * 时间
     */
    static int hour;

    /**
     * 计算八字
     *
     * @param birthday yyyy-MM-dd HH:mm:ss
     */
    public static String getBaZi(LocalDateTime birthday) {

        //把字符串转换为Date时间
        String format = DateUtil.format(birthday, "yyyy-MM-dd HH:mm");
        DateTime parse = DateUtil.parse(format, "yyyy-MM-dd HH:mm");
        Date birthdayDate = parse.toJdkDate();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(birthdayDate);

        ChineseDate date = new ChineseDate(birthdayDate);
        chineseMonth = date.getMonth();
        chineseDay = date.getDay();
        //取年份
        year = calendar.get(Calendar.YEAR);
        yearTwo = Integer.parseInt(String.valueOf(year).substring(2, 4));
        twoYear = Integer.parseInt(String.valueOf(year).substring(0, 2));
        //取月份
        month = calendar.get(Calendar.MONTH) + 1;
        //取几号
        day = calendar.get(Calendar.DAY_OF_MONTH);
        //取几点
        hour = calendar.get(Calendar.HOUR_OF_DAY);
        //取分
        int minute = calendar.get(Calendar.MINUTE);
        //世纪
        century = (year + 99) / 100;
        //计算年天干地支
        String computeYearString = computeYear(year);
        String computeMonthString = computeMonth(computeYearString);
        String computeDay = computeDay();
        String computeTime = computTime(computeDay, hour);

        return computeYearString + " " + computeMonthString + " " + computeDay + " " + computeTime;
    }

    /**
     * 计算年对应的天干地支
     *
     * @param year 年
     * @return String
     */
    private static String computeYear(int year) {
        //计算年的天干
        int yearHeavenlyStemsNum = (year - 3) % 10;
        if (yearHeavenlyStemsNum == 0) {
            yearHeavenlyStemsNum = 10;
        }

        // 因为数组下标是从零开始的，所以要减去1
        String yearHeavenlyStems = tenHeavenlyStems[yearHeavenlyStemsNum - 1];
        //计算年的地支
        int yearEarthlyBranches = (year - 3) % 12;
        //计算月天干地支
        if (yearEarthlyBranches == 0) {
            yearEarthlyBranches = 12;
        }
        //因为数组下标是从零开始的，所以要减去1
        String yearEarthlyBranch = twelveEarthlyBranches[yearEarthlyBranches - 1];
        return yearHeavenlyStems + yearEarthlyBranch + "年";
    }

    /**
     * 计算月对应的天干地支 获取年的天干，完后和阴历的月数
     * 若遇甲或己的年份，正月是丙寅；遇上乙或庚之年，正月为戊寅；遇上丙或辛之年，正月为庚寅；遇上丁或壬之年，正月为壬寅；遇上戊或癸之年，正月为甲寅。依照正月之干支，其余月份按干支推算即可
     */
    private static String computeMonth(String yearHeavenlyStems) {
        String subYear = yearHeavenlyStems.substring(0, 1);
        int zero = 0;
        if ("甲".equals(subYear) || "己".equals(subYear)) {
            zero = 2;
        } else if ("乙".equals(subYear) || "庚".equals(subYear)) {
            zero = 4;
        } else if ("丙".equals(subYear) || "辛".equals(subYear)) {
            zero = 6;
        } else if ("丁".equals(subYear) || "壬".equals(subYear)) {
            zero = 8;
        }
        for (int i = 0; i < 12; i++) {
            int HeavenlyStems = (i + zero) % 10;
            int EarthlyBranches = (i + 2) % 12;

            if (i == chineseMonth - 1) {
                return tenHeavenlyStems[HeavenlyStems] + twelveEarthlyBranches[EarthlyBranches] + "月";
            }
        }
        return null;
    }

    /**
     * 计算日对应的天干地支 干支纪日法 从已知日期计算干支纪日的公式为：
     * <p>
     * <p>天干 = (4 * C + [C / 4] + 5 * y + [y / 4] + [3 * (M + 1) / 5] + d - 3) % 10
     * <p>
     * <p>地支 = (8 * C + [C / 4] + 5 * y + [y / 4] + [3 * (M + 1) / 5] + d + 7 + i) % 12
     * <p>
     * <p>注意： [] 里的除法取整即可 1 说明如下：
     * <p>
     * <p>c 为年份前两位，比如 2019 年则 c 为 20 y 为年份后两位，比如 2019 年则 y 为 19 M 为月份，1 月和 2 月按上一年的 13 月和 14 月来算 d 为日数
     * i 奇数月为 0 偶数月为 6 比如计算 2020 年 2 月 9 日的干支日如下：
     * <p>
     * <p>天干 = (4 * 20 + 20 / 4 + 5 * 19 + 19 / 4 + 3 * (14 + 1) / 5 + 9 - 3) % 10 = 9 即 壬 地支 = (8 *20
     * + 20 / 4 + 5 * 19 + 19 / 4 + 3 * (14 + 1) / 5 + 9 + 7 + 6) % 12 = 7 即 午
     */
    private static String computeDay() {
        int mon = month;
        if (month == 1) {
            mon = 13;
        } else if (month == 2) {
            mon = 14;
        }
        int heavenlyStemsDay =
                (4 * twoYear + (twoYear / 4) + (5 * yearTwo) + (yearTwo / 4) + 3 * (mon + 1) / 5 + day - 3)
                        % 10;
        int i = 0;
        if (month % 2 == 0) {
            i = 6;
        }
        int earthlyBranchesDay =
                (8 * twoYear + twoYear / 4 + 5 * yearTwo + yearTwo / 4 + 3 * (mon + 1) / 5 + day + 7 + i)
                        % 12;
        return tenHeavenlyStems[heavenlyStemsDay - 1]
                + twelveEarthlyBranches[earthlyBranchesDay - 1]
                + "日";
    }

    /**
     * 获取记时
     * <p>
     * <p>子时 23 - 01 丑时 01 - 03 寅时 03 - 05 卯时 05 - 07 辰时 07 - 09 巳时 09 - 11 午时 11 - 13 未时 13 - 15 申时
     * 15 - 17 酉时 17 - 19 戌时 19 - 21 亥时 21 - 23
     * <p>
     * <p>根据上表可以得出生辰八字的第八个字，比如早上 11 点出生即第八个字为 午
     * https://jingyan.baidu.com/article/4d58d5416209f29dd4e9c0f7.html
     *
     * @param heavenlyStemsDay
     * @param hour
     * @return
     */
    private static String computTime(String heavenlyStemsDay, int hour) {
        // 计算时辰
        String subDay = heavenlyStemsDay.substring(0, 1);
        int twelveEarthlyBranchesNum = 0;
        if (hour >= 23 || hour < 1) {
            twelveEarthlyBranchesNum = 0;
        } else if (hour >= 1 && hour < 3) {
            twelveEarthlyBranchesNum = 1;
        } else if (hour >= 3 && hour < 5) {
            twelveEarthlyBranchesNum = 2;
        } else if (hour >= 5 && hour < 7) {
            twelveEarthlyBranchesNum = 3;
        } else if (hour >= 7 && hour < 9) {
            twelveEarthlyBranchesNum = 4;
        } else if (hour >= 9 && hour < 11) {
            twelveEarthlyBranchesNum = 5;
        } else if (hour >= 11 && hour < 13) {
            twelveEarthlyBranchesNum = 6;
        } else if (hour >= 13 && hour < 15) {
            twelveEarthlyBranchesNum = 7;
        } else if (hour >= 15 && hour < 17) {
            twelveEarthlyBranchesNum = 8;
        } else if (hour >= 17 && hour < 19) {
            twelveEarthlyBranchesNum = 9;
        } else if (hour >= 19 && hour < 21) {
            twelveEarthlyBranchesNum = 10;
        } else if (hour >= 21 && hour < 23) {
            twelveEarthlyBranchesNum = 11;
        }

        int itgFlag = 8;
        if ("甲".equals(subDay) || "己".equals(subDay)) {
            // 甲
            itgFlag = 0;
        } else if ("乙".equals(subDay) || "庚".equals(subDay)) {
            // 丙
            itgFlag = 2;
        } else if ("丙".equals(subDay) || "辛".equals(subDay)) {
            // 戊
            itgFlag = 4;
        } else if ("丁".equals(subDay) || "壬".equals(subDay)) {
            // 庚
            itgFlag = 6;
        } else if ("戊".equals(subDay) || "癸".equals(subDay)) {
            // 壬
            itgFlag = 8;
        }
        return tenHeavenlyStems[(twelveEarthlyBranchesNum + itgFlag) % 10]
                + twelveEarthlyBranches[twelveEarthlyBranchesNum]
                + "时";
    }
}